package com.lefeng.cockpit.datax.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.didiglobal.logi.security.common.PagingData;
import com.didiglobal.logi.security.common.Result;
import com.didiglobal.logi.security.common.enums.ConfigStatusEnum;
import com.didiglobal.logi.security.util.CopyBeanUtil;
import com.lefeng.cockpit.common.bean.dto.datasource.DataSourceDTO;
import com.lefeng.cockpit.common.bean.po.datasource.DataSourcePO;
import com.lefeng.cockpit.common.bean.vo.datasource.DataSourceVO;
import com.lefeng.cockpit.common.constant.Constants;
import com.lefeng.cockpit.common.constant.JdbcConstants;
import com.lefeng.cockpit.common.enums.DataSourceStatusEnum;
import com.lefeng.cockpit.common.enums.ResultCode;
import com.lefeng.cockpit.common.utils.JsonUtils;
import com.lefeng.cockpit.common.utils.ResultUtil;
import com.lefeng.cockpit.datax.dao.DataSourceDao;
import com.lefeng.cockpit.datax.service.DataSourceService;
import com.lefeng.cockpit.datax.tool.query.BaseQueryTool;
import com.lefeng.cockpit.datax.tool.query.MongoDBQueryTool;
import com.lefeng.cockpit.datax.tool.query.QueryToolFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author weifw_in
 */
@Service
@Transactional(readOnly = true)
@Slf4j
public class DataSourceServiceImpl implements DataSourceService {

    private static final String NOT_EXIST = "数据源不存在";

    @Resource
    private DataSourceDao dataSourceDao;

    @Override
    public Boolean dataSourceTest(DataSourceDTO dataSourceDTO) {
//
//        if (JdbcConstants.HBASE.equals(dataSourceDTO.getDsType())) {
//            try {
//                return new HBaseQueryTool(dataSourceDTO).dataSourceTest();
//            } catch (Exception e) {
//                e.printStackTrace();
//                return false;
//            }
//        }
        if (JdbcConstants.MONGODB.equals(dataSourceDTO.getDsType())) {
            try {
                return new MongoDBQueryTool(dataSourceDTO).dataSourceTest(dataSourceDTO.getDbName());
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
        BaseQueryTool queryTool;
        try {
            queryTool = QueryToolFactory.getByDbType(dataSourceDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return queryTool.dataSourceTest();
    }


    @Override
    public PagingData<DataSourceVO> pagingDataSource(DataSourceDTO queryDTO) {
        IPage<DataSourcePO> dataSourcePOs = dataSourceDao.selectPage(queryDTO);
        List<DataSourceVO> dataSourceVOS = CopyBeanUtil.copyList(dataSourcePOs.getRecords(), DataSourceVO.class);
        return new PagingData<>(dataSourceVOS, dataSourcePOs);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Integer> addDataSource(DataSourceDTO dataSourceDTO) {
        Result<Void> checkResult = checkParam(dataSourceDTO);
        if (checkResult.failed()) {
            log.warn("class=DataSourceServiceImpl||method=addDataSource||msg={}||msg=check fail!",
                    checkResult.getMessage());
            return Result.buildFrom(checkResult);
        }

        try {
            initDataSource(dataSourceDTO);
        } catch (IllegalArgumentException e) {
            return ResultUtil.build(ResultCode.UNSUPPORTED_DB_TYPE);
        }


        if (!dataSourceTest(dataSourceDTO)) {
            return ResultUtil.build(ResultCode.CONNECTION_FAILED);
        }

        DataSourcePO oldDataSource = dataSourceDao.getByDataSourceName(dataSourceDTO.getDsName());
        if (oldDataSource != null) {
            return Result.buildDuplicate("数据源名称重复");
        }

        DataSourcePO param = CopyBeanUtil.copy(dataSourceDTO, DataSourcePO.class);

        dataSourceDao.insert(param);
        return Result.buildSucc(param.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> delDataSource(Integer id) {
        DataSourcePO dataSourcePO = dataSourceDao.getById(id);
        if (dataSourcePO == null) {
            return Result.buildNotExist(NOT_EXIST);
        }

        return Result.build(1 == dataSourceDao.deleteById(dataSourcePO.getId()));
    }

    @Override
    public Result<Void> switchDataSource(Integer id, Integer status) {
        DataSourcePO dataSourcePO = dataSourceDao.getById(id);
        if (dataSourcePO == null) {
            return Result.buildNotExist(NOT_EXIST);
        }

        DataSourceStatusEnum statusEnum = DataSourceStatusEnum.valueOf(status);
        if (statusEnum == null) {
            return Result.buildParamIllegal("状态非法");
        }

        dataSourcePO.setStatus(status);
        return Result.build(1 == dataSourceDao.updateById(dataSourcePO));
    }

    @Override
    public Result<Void> editDataSource(DataSourceDTO dataSourceDTO) {
        if (StringUtils.isBlank(dataSourceDTO.getDsName())) {
            return Result.buildParamIllegal("数据源名为空");
        }

        if (ConfigStatusEnum.NORMAL.getCode() != dataSourceDTO.getStatus()
                && ConfigStatusEnum.DISABLE.getCode() != dataSourceDTO.getStatus()) {
            return Result.buildParamIllegal("状态只能是1或者2");
        }

        DataSourcePO dataSourcePO = dataSourceDao.getById(dataSourceDTO.getId());
        if (dataSourcePO == null) {
            Result<Integer> retAdd = addDataSource(dataSourceDTO);
            return Result.buildFrom(retAdd);
        }

        boolean succ = (1 == dataSourceDao.update(CopyBeanUtil.copy(dataSourceDTO, DataSourcePO.class)));
        return Result.build(succ);
    }

    @Override
    public List<String> listDataSourceTypes() {
        return dataSourceDao.listDistinctTypes();
    }

    @Override
    public Result<Integer> cloneDataSource(DataSourceDTO dataSourceDTO) {

        DataSourcePO dataSourcePO = dataSourceDao.getById(dataSourceDTO.getId());
        if (dataSourcePO == null) {
            return Result.buildNotExist("数据源不存在");
        }

        DataSourceDTO newDsPO = CopyBeanUtil.copy(dataSourcePO, DataSourceDTO.class);
        newDsPO.setDsName(dataSourceDTO.getDsName());
        newDsPO.setId(null);
        return addDataSource(newDsPO);
    }

    @Override
    public Result<List<DataSourcePO>> getAllDataSource(DataSourceDTO dataSourceDTO) {
        if (StringUtils.isBlank(dataSourceDTO.getDsType())) {
            return Result.buildParamIllegal("数据源类型不能为空");
        }
        return Result.buildSucc(dataSourceDao.getAllDataSource(dataSourceDTO));
    }

    /******************************************* private method **************************************************/
    private Result<Void> checkParam(DataSourceDTO dataSource) {
        if (null == dataSource) {
            return Result.buildParamIllegal("【数据源信息为空】");
        }
        if (StringUtils.isBlank(dataSource.getDsName())) {
            return Result.buildParamIllegal("【数据源名称为空】");
        }
        if (StringUtils.isBlank(dataSource.getDsType())) {
            return Result.buildParamIllegal("【数据源类型名字为空】");
        }
        return Result.buildSucc(null);
    }

    private void initDataSource(DataSourceDTO dataSourceDTO) throws IllegalArgumentException {
        if (dataSourceDTO.getStatus() == null) {
            dataSourceDTO.setStatus(DataSourceStatusEnum.NORMAL.getCode());
        }

        String url;
        String driverClass;
        // 构建基本 JDBC URL
        switch (dataSourceDTO.getDsType().toLowerCase()) {
            case JdbcConstants.MYSQL:
                url = String.format("jdbc:mysql://%s:%s/%s", dataSourceDTO.getIpAddress(), dataSourceDTO.getPort(), dataSourceDTO.getDbName());
                driverClass = JdbcConstants.MYSQL_DRIVER_6;
                break;
            case JdbcConstants.ORACLE:
                url = String.format("jdbc:oracle:thin:@%s:%s:%s", dataSourceDTO.getIpAddress(), dataSourceDTO.getPort(), dataSourceDTO.getDbName());
                driverClass = JdbcConstants.ORACLE_DRIVER2;
                break;
            case JdbcConstants.POSTGRESQL:
                url = String.format("jdbc:postgresql://%s:%s/%s", dataSourceDTO.getIpAddress(), dataSourceDTO.getPort(), dataSourceDTO.getDbName());
                driverClass = JdbcConstants.POSTGRESQL_DRIVER;
                break;
            case JdbcConstants.SQL_SERVER:
                url = String.format("jdbc:sqlserver://%s:%s;databaseName=%s", dataSourceDTO.getIpAddress(), dataSourceDTO.getPort(), dataSourceDTO.getDbName());
                driverClass = JdbcConstants.SQL_SERVER_DRIVER;
                break;
            case JdbcConstants.HIVE:
                url = String.format("jdbc:hive2://%s:%s/%s", dataSourceDTO.getIpAddress(), dataSourceDTO.getPort(), dataSourceDTO.getDbName());
                driverClass = JdbcConstants.HIVE_DRIVER;
                break;
            case JdbcConstants.PHOENIX:
                url = String.format("jdbc:phoenix:%s:%s:%s", dataSourceDTO.getIpAddress(), dataSourceDTO.getPort(), Constants.HBASE_UNSECURE);
                driverClass = JdbcConstants.PHOENIX_DRIVER;
                break;
            case JdbcConstants.CLICKHOUSE:
                url = String.format("jdbc:clickhouse://%s:%s/%s", dataSourceDTO.getIpAddress(), dataSourceDTO.getPort(), dataSourceDTO.getDbName());
                driverClass = JdbcConstants.CLICKHOUSE_DRIVER;
                break;
            default:
                throw new IllegalArgumentException("不支持的数据库类型");
        }

        // 添加自定义参数
        if (ObjectUtil.isNotNull(dataSourceDTO.getCustomParams()) && dataSourceDTO.getCustomParams().size() > 0) {
            String dbParams = JsonUtils.convertJsonToQueryString(dataSourceDTO.getCustomParams());
            url += (url.contains("?") ? "&" : "?") + dbParams;
        }

        dataSourceDTO.setUrl(url);
        dataSourceDTO.setDriverClass(driverClass);
    }

}